#ifndef __MODBUS_H__
#define __MODBUS_H__
#include "typedef.h"
#define MODBUS_CRC_SIZE         2       /* or 16-bit, in low-high order */

#define FUNC_NONE               0x00

#define FUNC_READ_COILS         0x01
#define FUNC_WRITE_COIL         0x05
#define FUNC_WRITE_COIL_ERR     0x85
#define FUNC_WRITE_MCOIL        0x0F    /* multiple coils */
#define FUNC_WRITE_MCOIL_ERR    0x8F

#define FUNC_READ_DISCRETES     0x02
#define FUNC_READ_DISCRETES_ERR 0x82

#define FUNC_READ_INPUTS        0x04
#define FUNC_READ_INPUTS_ERR    0x84

#define FUNC_READ_HOLDINGS      0x03
#define FUNC_WRITE_HOLDING      0x06
#define FUNC_WRITE_MHOLDINGS    0x10
#define FUNC_READ_HOLDINGS_ERR  0x83
#define FUNC_WRITE_HOLDING_ERR  0x86
#define FUNC_WRITE_HOLDINGS_ERR 0x90

/*
 *-------------------------------------------------------------------------
 * Modbus error response codes
 *-------------------------------------------------------------------------
 */
#define MODBUS_GOOD             0       // No error found (temporarily)
#define MODBUS_ILL_FUNC         1       // Illegal Function
#define MODBUS_ILL_DATA_ADDR    2       // Illegal Data Address
#define MODBUS_ILL_DATA_VALUE   3       // Illegal Data Value
#define MODBUS_SLAVE_FAILURE    4       // Slave Device Failure
#define MODBUS_ACKNOWLEDGE      5       // Slave has accepted request and
                                        // is processing it, but a long 
                                        // duration of time is required. 
                                        // This response is returned to 
                                        // prevent a timeout error from 
                                        // occurring in the master. Master 
                                        // can next issue a Poll Program 
                                        // Complete message to determine 
                                        // whether processing is completed
#define MODBUS_SLAVE_BUSY       6       // Slave is engaged in processing 
                                        // a long-duration command. Master 
                                        // should retry later
#define MODBUS_NAK              7       // Negative Acknowledge; Slave 
                                        // cannot perform the programming 
                                        // functions. Master should request
                                        // diagnostic or error information 
                                        // from slave
#define MODBUS_PARITY_ERROR     8       // Slave detected a parity error in 
                                        // memory. Master can retry the 
                                        // request, but service may be 
                                        // required on the slave device
#define MODBUS_PATH             10      // Gateway Path Unavailable. 
                                        // Specialized for Modbus gateways.
                                        // Indicates a misconfigured gateway
#define MODBUS_TARGET           11 	    // Gateway Target Device Failed to 
                                        // Respond. Specialized for Modbus 
                                        // gateways. Sent when slave fails 
                                        // to respond
/*
 * Conventions:
 *     xxxx_f:      a frame format from the master to the slave as commands
 *     xxxx_r:      a frame format from the slave to the master as replies
 */
/*
 *-------------------------------------------------------------------------
 * Modbus generic frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code */
    uint16_t start;        /* start register address (starting at 0th) */
    uint16_t qty;          /* quantity of coils */
} generic_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code */
    uint8_t  bytes;        /* byte count following */
} generic_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code */
    uint8_t  err_code;     /* the error code (generally 1, 2, 3, or 4) */
} generic_err_r;


/*
 *-------------------------------------------------------------------------
 * Modbus read-coil frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x01 */
    uint16_t start;        /* start coil address (starting at 0th) */
    uint16_t qty;          /* quantity of coils */
} read_coil_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x01 */
    uint8_t  bytes;        /* byte count that follows */
} read_coil_r;

/*
 *-------------------------------------------------------------------------
 * Modbus write-single-coil  frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x05 */
    uint16_t start;        /* target coil address */
    uint16_t on_off;       /* 0xFF00=on; 0x0000=off */
} write_coil_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x05 */
    uint16_t start;        /* target coil address */
    uint16_t on_off;       /* 0xFF00=on; 0x0000=off */
} write_coil_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x85 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} write_coil_err_r;

/*
 *-------------------------------------------------------------------------
 * Modbus write-multiple-coils frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x0F */
    uint16_t start;        /* starting target coil address */
    uint16_t qty;          /* quantity of coils to write */
    uint8_t  bytes;        /* byte count that follows (ie string of bytes) */
} write_mcoil_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x0F */
    uint16_t start;        /* starting target coil address */
    uint16_t qty;          /* quantity of coils written */
} write_mcoil_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x8F */
    uint8_t  err_code;     /* error (1/2/3/4) */
} write_mcoil_err_r;


#define MAX_COILS               0x7D0   /* num of 1~2000 to read */
#define MAX_MCOILS              0x7B0   /* num of 1~1968 to write */

/*
 *-------------------------------------------------------------------------
 * Modbus read-discrete-inputs frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x02 */
    uint16_t start;        /* start register address (starting at 0th) */
    uint16_t qty;          /* quantity of coils */
} read_discrete_f, read_disc_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x02 */
    uint8_t  bytes;        /* byte count following */
} read_discrete_r, read_disc_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x82 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} read_discrete_err_r, read_disc_err_r;


/*
 *-------------------------------------------------------------------------
 * Modbus read-input-registers frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x04 */
    uint16_t start;        /* 0~0xFFFF */
    uint16_t qty;          /* 1~125 */
} read_input_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x04 */
    uint8_t  bytes;        /* byte count following */
} read_input_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x84 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} read_input_err_r;

#define MAX_INPUTS              0x7D            // num of 1~125 to read
/*
 *-------------------------------------------------------------------------
 * Modbus read-holding-registers frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x03 */
    uint16_t start;        /* start holding register address (0~0xFFFF) */
    uint16_t qty;          /* 1~125 */
} read_holds_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x03 */
    uint8_t  bytes;        /* byte count that follows (=qty*2) */
} read_holds_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x83 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} read_holds_err_r;

/*
 *-------------------------------------------------------------------------
 * Modbus write-single-holding-register frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x06 */
    uint16_t start;        /* target holding register address */
    uint16_t value;        /* the value to write */
} write_hold_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x06 */
    uint16_t start;        /* target holding register address */
    uint16_t value;        /* the value written */
} write_hold_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x86 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} write_hold_err_r;

/*
 *-------------------------------------------------------------------------
 * Modbus write-multiple-holding-registers frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x10 */
    uint16_t start;        /* target holding register address */
    uint16_t qty;          /* quantity of holding registers to write */
    uint8_t  bytes;        /* byte count that follows */
} write_mholds_f;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x10 */
    uint16_t start;        /* target holding register address */
    uint16_t qty;          /* quantity of holding registers written */
} write_mholds_r;

typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x90 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} write_mholds_err_r;

/*
 *-------------------------------------------------------------------------
 * Modbus write-multiple-holding-registers frame format
 *-------------------------------------------------------------------------
 */
typedef struct {
    uint8_t  addr;         /* slave address */
    uint8_t  func;         /* the function code, i.e. 0x90 */
    uint8_t  err_code;     /* error (1/2/3/4) */
} crc_err_r;

#define MAX_HOLDINGS_R          0x7D            // num of regs to read
#define MAX_HOLDINGS_W          0x7B            // num of regs to write

#endif  /* __MODBUS_H__ */
